import { useUserStore } from '@/stores/modules/user'
import router from '@/router'
import axios from 'axios'
import type { AxiosRequestConfig } from 'axios'

// 自定义业务数据的响应格式，code为0表示业务成功
interface ApiDataResponse<T = any> {
  code: number
  message: string
  data: T
}

/**
 * 创建axios实例，配置基础路径
 */
const request = axios.create({
  baseURL: import.meta.env.VITE_APP_BASE_API,
  timeout: 8000,
  headers: {
    'Content-Type': 'application/json',
  },
  responseType: 'json',
  responseEncoding: 'utf-8',
})

/**
 * 请求拦截器
 */
request.interceptors.request.use(
  // 发送请求前
  async function (config) {
    const userStore = useUserStore()

    if (userStore.token) {
      config.headers.Authorization = userStore.token
    }
    return config
  },
  // 请求失败
  function (err) {
    console.error('请求拦截器错误', err)
    return Promise.reject(err)
  },
)

/**
 * 响应拦截器
 */
request.interceptors.response.use(
  // res.status===2xx，表示http响应成功
  function (res) {
    return res // 保留 AxiosResponse 类型，不做解包
  },
  // res.status!==2xx，表示http响应失败
  function (err) {
    console.error('响应拦截器错误', err)

    if (err.response?.status === 401) {
      // 清除用户信息
      const userStore = useUserStore()
      userStore.logout()
      // 跳转登录，带上接口失效所在页面的地址，登录完成后回跳使用
      router.push(`/login?returnUrl=${router.currentRoute.value.fullPath}`)
    }

    const msg = handleAxiosError(err)
    showFailToast(msg)
    return Promise.reject(err)
  },
)

/**
 * 请求封装
 * @param config 请求配置
 * @returns 返回业务数据
 */
async function apiRequest<T = any>(config: AxiosRequestConfig): Promise<T> {
  const res = await request(config)
  const { code, message, data } = res.data as ApiDataResponse<T>

  // res.status===2xx，表示http响应成功
  // 但是res.data.code !==0，表示业务异常
  if (code !== 0) {
    showFailToast(message || '业务异常')
    return Promise.reject(new Error(message || '业务异常'))
  }

  return data // 返回真正业务数据
}

/**
 * 上传文件，带进度
 */
async function uploadFile(
  url: string,
  data: FormData,
  onProgress: (percent: number) => void,
): Promise<any> {
  try {
    const res = await request.post(url, data, {
      onUploadProgress: (progressEvent) => {
        const { loaded, total } = progressEvent
        if (typeof total === 'number' && total > 0) {
          const percent = Math.floor((loaded * 100) / total)
          onProgress(percent)
        }
      },
    })
    return res.data
  } catch (err) {
    console.error('文件上传失败：', err)
    throw err // 仍然抛出去，调用方能处理
  }
}

/**
 * 下载文件（支持进度回调）
 * @param url 下载地址
 * @param params 请求参数（可选）
 * @param filename 下载保存的文件名（可选，默认从响应 header 中获取）
 * @param onProgress 下载进度回调（可选）
 */
async function downloadFile(
  url: string,
  params: Record<string, any> = {},
  filename?: string,
  onProgress?: (percent: number) => void,
): Promise<void> {
  try {
    const response = await request.get(url, {
      params,
      responseType: 'blob',
      onDownloadProgress: (progressEvent) => {
        const { loaded, total } = progressEvent
        if (typeof total === 'number' && total > 0) {
          const percent = Math.floor((loaded * 100) / total)
          onProgress?.(percent)
        }
      },
    })

    const blob = new Blob([response.data])
    let downloadName = filename || 'download'
    const disposition = response.headers['content-disposition']
    if (disposition) {
      const match = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/.exec(disposition)
      if (match?.[1]) downloadName = decodeURIComponent(match[1].replace(/['"]/g, ''))
    }

    const link = document.createElement('a')
    link.href = URL.createObjectURL(blob)
    link.download = downloadName
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
    URL.revokeObjectURL(link.href)
  } catch (err) {
    console.error('文件下载失败：', err)
    throw err // 仍然抛出去，调用方能处理
  }
}

/**
 * 处理 axios 错误
 * @param error 错误信息
 * @returns 错误提示信息
 */
function handleAxiosError(error: unknown): string {
  // axios 错误
  if (axios.isAxiosError(error)) {
    const codeMap: Record<string, string> = {
      ECONNABORTED: '请求超时，请稍后重试',
      ERR_NETWORK: '网络异常，请检查网络连接',
      ERR_BAD_REQUEST: '错误的请求参数',
      ERR_BAD_RESPONSE: '服务器响应异常',
      ERR_FR_TOO_MANY_REDIRECTS: '请求被重定向次数过多',
      ERR_INVALID_URL: '请求地址不合法',
      ERR_CANCELED: '请求被取消',
    }

    // 优先用 code 提示，如果没有匹配再退回 message
    if (error.code && codeMap[error.code]) {
      return codeMap[error.code]
    }

    // 如果 response 存在，可以再判断 status
    if (error.response) {
      const status = error.response.status
      if (status === 401) return '登录已失效，请重新登录'
      if (status === 403) return '权限不足，无法访问'
      if (status === 404) return '请求资源不存在'
      if (status >= 500) return '服务器异常，请稍后再试'

      return error.response.data?.message || '请求失败'
    }

    // fallback 到 error.message 作为兜底（只用于开发调试或内部日志）
    return error.message || '未知错误'
  }

  // 非 axios 错误
  return '发生了未知错误'
}

export { apiRequest, uploadFile, downloadFile }
